/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */

package org.ponly.cta4j.service;

import org.ponly.cta4j.Captcha;
import org.ponly.cta4j.CaptchaFactory;
import org.ponly.cta4j.service.store.CaptchaStore;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Locale;

/**
 * store="redis://10.10.0.101:"
 * store="memcached://10.10.0.102:11211"
 * store="ehcache/captcha"
 * store="memory"
 * <cta4j:service id="" class="" store="" factory="" />
 * <cta4j:service id="" class="" store-ref="" factory-ref="" />
 */
public abstract class AbstractCaptchaService implements CaptchaService {
    /**
     * 验证码存储设备.
     */
    protected CaptchaStore store;

    /**
     * 验证码工厂.
     */
    protected CaptchaFactory factory;

    /**
     * 使用给定的配置创建一个验证码服务.
     *
     * @param captchaStore   验证码存储设备
     * @param captchaFactory 验证码工厂
     */
    public AbstractCaptchaService(final CaptchaStore captchaStore, final CaptchaFactory captchaFactory) {
        this.store = captchaStore;
        this.factory = captchaFactory;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public BufferedImage getChallengeForId(final String id) {
        return getChallengeForId(id, null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public BufferedImage getChallengeForId(final String id, final Locale locale) {
        final CaptchaStore store = getCaptchaStore();

        Captcha captcha = store.get(id);
        // 不存在或脏读
        if (null == captcha || captcha.hasChallengeBeenCalled()) {
            // TODO 是否应该销毁后再存储.
            captcha = generateAndStore(id, locale);
        }

        final BufferedImage challenge = getChallengeClone(captcha);
        captcha.disposeChallenge();

        return challenge;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean validateResponseForId(final String id, final Object response) {
        final CaptchaStore store = getCaptchaStore();
        final Captcha captcha = store.get(id);
        if (null == captcha) {
            return false;
        } else {
            final boolean valid = captcha.validate(response);

            store.remove(id);
            return valid;
        }
    }

    /**
     * 生成并存储验证码.
     *
     * @param id     验证码 ticket
     * @param locale 验证码 locale
     * @return 验证码
     */
    protected Captcha generateAndStore(final String id, final Locale locale) {
        final Captcha captcha = null != locale ? factory.getCaptcha(locale) : factory.getCaptcha();

        getCaptchaStore().put(id, captcha);

        return captcha;
    }

    /**
     * 获取一个验证码的图片拷贝.
     *
     * @param captcha 验证码
     * @return 验证码图片拷贝
     */
    protected BufferedImage getChallengeClone(final Captcha captcha) {
        final BufferedImage challenge = captcha.getChallenge();
        final BufferedImage clone = new BufferedImage(challenge.getWidth(), challenge.getHeight(), challenge.getType());
        final Graphics2D g2d = clone.createGraphics();

        g2d.drawImage(challenge, 0, 0, clone.getWidth(), clone.getHeight(), null);
        g2d.dispose();

        return clone;
    }

    /**
     * @return 当前存储验证码的存储设备
     */
    public CaptchaStore getCaptchaStore() {
        return store;
    }

    /**
     * 设置存储验证码的存储设备.
     *
     * @param captchaStore CaptchaStore
     */
    public void setCaptchaStore(final CaptchaStore captchaStore) {
        this.store = captchaStore;
    }

    /**
     * @return 当前生成验证码的验证码工厂
     */
    public CaptchaFactory getCaptchaFactory() {
        return factory;
    }

    /**
     * 设置用于生成验证码的工厂.
     *
     * @param captchaFactory 验证码工厂
     */
    public void setCaptchaFactory(final CaptchaFactory captchaFactory) {
        this.factory = captchaFactory;
    }
}
